前端程式設計筆記 (2026.4)

HTML / CSS / JS / AJAX / Python Flask 職訓課程筆記彙整&快速工具

GARY-KAO

第十一章:JavaScript 表單事件監聽與資料處理

在前端開發中,表單驗證與資料的捕捉是非常重要的環節。透過 jQuery,我們可以輕鬆監聽使用者的輸入狀態,並決定是否允許表單送出。

1. 監聽 Form 內容與基礎驗證

A. 狀態旗標 (Flags) 與資料準備

在進行表單驗證時,我們通常會在全域宣告一組布林值(Boolean)變數作為「旗標」。只有當所有欄位都驗證成功(轉為 true),才允許表單送出。

// 宣告公有變數 (預設為 false,代表尚未通過驗證)
let flag_username01 = false;
let flag_password01 = false;
let flag_email01 = false;

// 模擬後端傳來的 JSON 陣列資料 (後續可用於渲染下拉選單)
const foodData = [
    {
        "name": "牛肉麵",
        "price": 150,
        "description": "經典紅燒湯頭搭配燉煮入味的牛肉與Q彈麵條。"
    },
    {
        "name": "雞排飯",
        "price": 120,
        "description": "香酥雞排搭配白飯與清爽配菜。"
    }
];

B. 表單送出監聽 (Submit) 與阻擋預設行為

傳統的 <form> 送出時會造成整個網頁重新整理。為了使用 AJAX 在背景傳遞資料,我們必須先阻擋這個預設行為。

$(function () {
    // 監聽 form 的 submit 事件
    $("#myForm").submit(function (e) {
        
        // 判斷所有欄位的旗標是否都為 true
        if (flag_username01 == true && flag_password01 == true && flag_email01 == true) {
            
            e.preventDefault(); // 阻擋表單預設的網頁重整行為
            
            console.log("form 觸發成功!");
            // 透過 .val() 提取使用者在 input 欄位中輸入的值
            console.log($("#username01").val());
            console.log($("#password01").val());
            console.log($("#email01").val());
            
            // 這裡可以接續寫 AJAX 程式碼將資料送往後端...
            
        } else {
            e.preventDefault(); // 即便驗證失敗,也要阻擋重整
            alert("欄位有錯誤, 請修正!");
        }
    });
});
💡 重點語法:e.preventDefault()
這是在處理表單送出(Submit)或超連結點擊(Click)時必備的指令,作用是「阻止瀏覽器執行該元素的預設動作」。

C. 狀態改變事件:Change vs Blur

在即時驗證使用者輸入的內容時,我們常使用以下兩種觸發時機:

  • change (內容改變): 當使用者在欄位內輸入內容,游標離開該欄位(失去焦點),系統偵測到內容與一開始不同時才會觸發。
  • blur (失去焦點): 不管使用者有沒有修改內容,只要游標一離開該欄位就會立刻觸發。常應用於「必填欄位防呆」,提醒使用者忘記填寫。
// 觸發條件:數值有變更 + 游標失去焦點
$("#password01").change(function () {
    console.log("密碼已變更:" + $("#password01").val());
});

// 觸發條件:單純游標失去焦點 (即刻觸發)
$("#email01").blur(function () {
    console.log("Email 欄位失去焦點:" + $("#email01").val());
});

D. 實戰範例:結合 Bootstrap 驗證類別與字數判斷

這是一個完整的欄位防呆應用。當使用者輸入完帳號並移開游標時(觸發 blur 事件),程式會立刻檢查字數是否合乎規定,並給予即時的視覺回饋(綠色勾勾或紅色叉叉),同時更新對應的過關旗標。

$("#username01").blur(function () {
    // 1. 取得當前輸入的字數
    // $(this) 代表觸發此事件的元素本身 (#username01)
    console.log("目前字數:" + $(this).val().length);

    // 2. 邏輯判斷:字數大於 0 且小於 7 (亦即 1~6 個字)
    if ($(this).val().length > 0 && $(this).val().length < 7) {
        
        // 符合規定:移除紅框,加上綠框 (Bootstrap 樣式)
        $(this).removeClass("is-invalid").addClass("is-valid");
        
        // 將該欄位的全域過關旗標設為 true
        flag_username01 = true; 
        
    } else {
        
        // 不符合規定:移除綠框,加上紅框
        $(this).removeClass("is-valid").addClass("is-invalid");
        
        // 將過關旗標設為 false,未來表單將無法送出
        flag_username01 = false; 
    }
});
  • $(this) 的妙用: 在 jQuery 事件中,$(this) 自動指向當下正在操作的元素。這能避免一直重複寫 $("#username01"),讓程式碼更簡潔、維護性更高。
  • 長度判斷: 利用 .val().length 抓取輸入字串的長度,作為 if...else 的判斷條件。
  • 動態切換樣式: 透過 removeClass()addClass() 的組合技,動態抽換 Bootstrap 的驗證類別。is-valid 會使框線變綠並顯示下方的 .valid-feedback 文字;is-invalid 則使框線變紅並顯示 .invalid-feedback 文字。


2. 表單樣式 (不使用 form) 與 AJAX 送出準備

在現代前端開發中,我們常會省略 <form> 標籤,直接使用一般的 <button type="button"> 來觸發資料送出。這樣做的好處是完全不需要處理網頁重新整理的問題 (不需寫 e.preventDefault()),非常適合搭配 AJAX 進行前後端分離的資料傳輸。

A. 實作邏輯與程式碼

以下範例為三個獨立欄位分別綁定 blur 事件進行即時驗證,最後透過一個獨立的按鈕點擊 (click) 來統整狀態並取得資料:

// 1. 針對各別欄位設定獨立的 blur (失去焦點) 驗證
$("#username02").blur(function () {
    // 帳號長度限制:1~6 個字
    if ($(this).val().length > 0 && $(this).val().length < 7) {
        $(this).removeClass("is-invalid").addClass("is-valid");
        flag_username02 = true;
    } else {
        $(this).removeClass("is-valid").addClass("is-invalid");
        flag_username02 = false;
    }
});

$("#password02").blur(function () {
    // 密碼長度限制:2~8 個字
    if ($(this).val().length > 1 && $(this).val().length < 9) {
        $(this).removeClass("is-invalid").addClass("is-valid");
        flag_password02 = true;
    } else {
        $(this).removeClass("is-valid").addClass("is-invalid");
        flag_password02 = false;
    }
});

$("#email02").blur(function () {
    // Email長度限制:2~10 個字
    if ($(this).val().length > 1 && $(this).val().length < 11) {
        $(this).removeClass("is-invalid").addClass("is-valid");
        flag_email02 = true;
    } else {
        $(this).removeClass("is-valid").addClass("is-invalid");
        flag_email02 = false;
    }
});

// 2. 監聽一般按鈕的點擊事件 (而非 form 的 submit)
$("#btn02").click(function () {
    // 檢查所有旗標是否皆為 true
    if (flag_username02 && flag_password02 && flag_email02) {
        console.log("按鈕點擊驗證通過,準備執行 AJAX!");
        // 蒐集所有資料準備打包給後端
        console.log($("#username02").val());
        console.log($("#password02").val());
        console.log($("#email02").val());
    } else {
        // 只要有一個旗標為 false,就擋下並提示使用者
        alert("欄位錯誤, 請修正!");
    }
});

B. 核心觀念解析

  • 個別欄位驗證 (Modularity): 將每個欄位的驗證邏輯拆開獨立處理,不僅讓程式碼更容易閱讀,未來若要修改單一欄位(如:帳號)的規則,也不會影響到其他欄位。
  • if (flag_A && flag_B) 縮寫寫法: 在 JavaScript 中,如果變數本身就是布林值 (Boolean),在 if 判斷式內可以省略 == true,直接寫變數名稱即可,這是一種更簡潔俐落的寫法。
  • 取代 Submit 的 Click 事件: 因為沒有 <form>,我們改用 $("#btn02").click(...) 來攔截使用者的送出意圖。在這個區塊內將所有 .val() 蒐集起來打包成 JSON 格式,就是前端串接後端 API (如 Python Flask) 的標準前置作業。


3. 動態渲染下拉選單 (Data Rendering)

在實務開發中,下拉選單的選項往往不是寫死的,而是從後端資料庫或 API 取得。透過 jQuery 的 empty()append() 方法,我們可以輕鬆地將資料陣列轉換成網頁上的選項。

A. 渲染邏輯三步驟

  1. 清空舊資料: 使用 .empty() 移除選單內原有的所有 <option>,避免新舊資料重複堆疊。
  2. 重置預設選項: 重新插入一筆帶有提示文字(如:***請選擇餐點***)且被 disabled 的選項。
  3. 迴圈跑資料: 使用 JavaScript 的 forEach 遍歷資料陣列,並將每一筆資料拼接到 HTML 字串中後 append 進選單。
// 渲染餐點選單實作
$("#myfood").empty(); // 步驟 1:清空

// 步驟 2:重置預設提示
$("#myfood").append(`<option value="" class="text-center" disabled selected>***請選擇餐點***</option>`);

// 步驟 3:遍歷陣列並動態渲染
foodData.forEach(function (item) {
    // 利用樣板字面值 (Template Literals) 拼接 HTML
    let strHTML = `<option value="${item.name}">${item.name}</option>`;
    $("#myfood").append(strHTML);
});

B. 核心語法解析

  • 樣板字面值 (Backticks): 使用反引號( ` )來撰寫字串。這讓我們可以直接在字串中換行,並透過 ${變數} 的語法輕鬆嵌入資料,取代傳統瑣碎的 + 號拼接。
  • forEach 迴圈: 這是處理陣列資料的標準方法。它會針對 foodData 內的每一筆物件執行一次函式,並將當下的資料賦予給參數(例如 item)。
  • 值變更監聽 (Change Event): 當使用者從下拉選單選擇了不同項目後,會觸發 change 事件。這通常用來即時取得使用者選取的值($(this).val()),以便進行後續運算或篩選。
// 監聽選單變更事件
$("#mycity").change(function () {
    // 當城市選單變更時,即時印出選取的值
    console.log("當前選擇的城市:" + $(this).val());
});

$("#myfood").change(function () {
    // 當餐點選單變更時,即時印出選取的值
    console.log("當前選擇的餐點:" + $(this).val());
});
💡 實戰小技巧:
在執行 append() 之前,務必記得先執行 empty()。如果少了清空的步驟,每次執行渲染函式時,選單的選項就會無限增加。

4. 滑桿用法與即時數值連動 (Range Input)

在使用 <input type="range"> 時,最核心的互動需求就是讓使用者在拖曳滑桿時,畫面上的數字能「同步」更新。這需要透過監聽 input 事件來達成。

A. 事件監聽:input vs. change

B. 實作邏輯與程式碼

假設 HTML 結構中有一個 ID 為 #num 的滑桿,以及一個用來顯示數字的 ID #num_text

// 監聽滑桿的 input 事件
$("#num").on("input", function () {
    // 1. 在主控台印出目前滑桿的數值
    console.log($(this).val());

    // 2. 將滑桿目前的數值 (.val()) 寫入到顯示文字的標籤 (.text()) 中
    $("#num_text").text($(this).val());
});

C. 重點解析

💡 實務開發提示:
在處理大量數據或繪圖(如地圖縮放、Canvas 繪圖)時,若 input 觸發過於頻繁導致效能下降,開發者有時會改用 change 或是加上防抖(Debounce)機制。但在一般表單數值顯示中,使用 input 效果最佳。


5. 單選 (Radio) 與 複選 (Checkbox) 的資料取值

在處理多選或單選元件時,我們不能只靠單一的 ID 取值,因為它們通常是一組具備相同 name 屬性的集合。關鍵在於利用 jQuery 的 :checked 選擇器來過濾出「被勾選」的項目。

A. 複選框 (Checkbox) 的多重取值邏輯

由於複選框允許選取多個項目,我們通常會準備一個空的「陣列 (Array)」來儲存結果,並搭配 each() 迴圈來遍歷所有被勾選的框。

// 1. 設定初始值 (在網頁載入時預先勾選)
$("input[name='sport'][value='跑步']").prop("checked", true);

// 2. 監聽確認按鈕
$("#btn06").click(function () {
    let result = []; // 準備一個空陣列來存放選中的運動

    // 使用 :checked 選擇器抓取所有被勾選的 sport
    $("input[name='sport']:checked").each(function () {
        // $(this) 代表當下這一個被勾選的 input
        console.log("選中值:" + $(this).val());
        result.push($(this).val()); // 將值存入陣列中
    });

    // 3. 簡單防呆驗證
    if (result.length == 0) {
        alert("至少選擇一個運動!");
    } else {
        console.log("最終勾選清單:", result);
    }
});

B. 單選框 (Radio) 的取值方法

單選框雖然在同一組 name 中只能選一個,但取值方式與複選框類似。使用 :checked 能確保我們抓到的是目前選中的那一筆。

// 1. 設定初始預設選中項
$("input[name='edu'][value = '高中職']").prop("checked", true);

// 2. 取出所選取的值
$("#btn07").click(function () {
    // 雖然單選只有一個值,但同樣可以使用 :checked 選擇器
    $("input[name='edu']:checked").each(function () {
        console.log("教育程度:" + $(this).val());
    });
});

C. 重點語法解析

  • .prop("checked", true) 這是操作元素屬性(Properties)的最佳方式。相較於 attr()prop() 更適合處理如 checked、disabled、selected 等具備布林值的狀態。
  • :checked 選擇器: 這是 jQuery 專門用來過濾「選取狀態」的偽類選擇器。它能讓我們只對有被勾選的元件進行操作。
  • result.push() JavaScript 陣列的標準方法,用來將新資料加入陣列的末端。在處理複選資料時,這能幫我們把分散的 input 值整理成一份乾淨的清單。
  • .each() 迴圈: 當 jQuery 選擇器選到多個元素時,使用 each() 可以逐一對這些元素執行指定的函式。